package squelette;

import java.util.ArrayList;
import java.util.Random;

import Lib3d.Vector3d;

/**
 * Classe simulant un poil composé de 4 masses :
 * - Une au centre (0,0,0), qui ne bouge pas (m1).
 * - Une attachée à un rayon donné, qui ne bouge pas (m2)
 * - Deux autres, mobiles, qui servent à visualiser le poil (m3, m4).
 * 
 * On les relie par des ressorts :
 * - Entre m1 et m2 (et inversement).
 * - Entre m2 et m3 (et inversement).
 * - Entre m3 et m4 (et inversement).
 * - Entre m2 et m4 (et inversement).
 * - Entre m1 et m3 (et inversement).
 */
public class Poil {

	private static final float GRAVITY_WEIGHT = -50.0f;
	
	private static Vector3d sphereSpeed = new Vector3d(0, 0, 0);	// Vitesse de la sphere actuellement traitée. Par soucis d'optimisation,
																	// on garde la même vitesse pour tes les poils d'une même sphere.
	public static void setSphereSpeed(Vector3d sphereSpeed) {
		Poil.sphereSpeed = sphereSpeed;
	}
		
	private ArrayList<Mass> massesDuPoil = new ArrayList<Mass>();
	private Mass m1;
	private Mass m2;
	private Mass m3;
	private Mass m4;
	
	private float r, g, b;

	private static Vector3d gravity = new Vector3d(0, GRAVITY_WEIGHT, 0);	// Vecteur gravité.

	public Poil(Vector3d vm1, Vector3d vm2, Vector3d vm3) {
		Random rand = new Random();
		setR(rand.nextFloat());
		setG(rand.nextFloat());
		setB(rand.nextFloat());
		
		m1 = new Mass(new Vector3d(0, 0, 0), true);		// Attachée au centre de la sphere
		m2 = new Mass(vm1, true);	// Attachée au rayon de la sphere
		m3 = new Mass(vm2, false);	// Non attachée.
		m4 = new Mass(vm3, false);	// Non attachée.
		
		massesDuPoil.add(m1);
		massesDuPoil.add(m2);
		massesDuPoil.add(m3);
		massesDuPoil.add(m4);
		
		m1.addNeighbourMasses(m3);
		m3.addNeighbourMasses(m1);
		
		m2.addNeighbourMasses(m3);
		m3.addNeighbourMasses(m2);
		m2.addNeighbourMasses(m4);
		m4.addNeighbourMasses(m2);
		
		m3.addNeighbourMasses(m4);
		m4.addNeighbourMasses(m3);
	}
	
	public float getB() {
		return b;
	}

	public void setB(float b) {
		this.b = b;
	}

	public float getG() {
		return g;
	}

	public void setG(float g) {
		this.g = g;
	}

	public float getR() {
		return r;
	}

	public void setR(float r) {
		this.r = r;
	}

	/**
	 * Calcule la somme des forces qui s'exercent sur les masses du poil.
	 */
	public void calculateSumForces() {
		// Resette les forces des masses.
		for (Mass m : massesDuPoil) {
			m.resetForce();
		}
		
		// Pour chaque masse, calcule la force exercée sur lui par ses voisins
		// et l'ajoute à sa force interne.
		for (Mass m : massesDuPoil) {
			m.addForceFromNeighbours();
		}

		// Ajout une force "gravité" et de vitesse de la sphère à laquelle ils sont liées sur chaque point
		for (Mass m : massesDuPoil) {
			m.addForce(gravity);
			m.addForce(Vector3d.neg(sphereSpeed));	// Ajoute l'inverse de vitesse.
		}

		// Euler (slide 141) :
		// v(t+dt) = dt/m * somme des forces exercées sur i + v(t)
		for (Mass m : massesDuPoil) {
			Vector3d vtpdt = Vector3d.mul(m.getForce(), (JavaRenderer.TIME_SCALE / Mass.weight));
			vtpdt = Vector3d.add(vtpdt, m.getSpeed());
			m.setNewSpeed(vtpdt);
		}
		
		// Euler (slide 140) :
		for (Mass m : massesDuPoil) {
			Vector3d newPosition = Interpolateur.interpoler(
					m.getPosition(), m.getSpeed(), m.getNewSpeed(), JavaRenderer.TIME_SCALE
			);
			
			m.setPosition(newPosition);
			
			// Fin : La vitesse actuelle devient égale à la vitesse nouvellement calculée.
			m.setSpeedToNewSpeed();
		}
	}
	
	/*
	 * Retourne la premiere masse à afficher.
	 */
	public Mass getMasse1ToDraw() {
		return m2;
	}
	
	/*
	 * Retourne la deuxième masse à afficher.
	 */
	public Mass getMasse2ToDraw() {
		return m3;
	}
	
	/*
	 * Retourne la troisième masse à afficher.
	 */
	public Mass getMasse3ToDraw() {
		return m4;
	}
}
